package com.tdam.g12.util;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlSerializer;

import android.util.Xml;

public class MessageSenderClient {

	private final static SimpleDateFormat dateformat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
	
	public MessageSenderClient() {
	}
	
	public static String getTimestamp(Date timestamp){
		return dateformat.format(timestamp);
	}
	public static Date getTimestamp(String timestamp){
		try
		{
			return dateformat.parse(timestamp);
		} catch (ParseException e)
		{
			e.printStackTrace();
			return null;
		}
	}
	
	public static ArrayList<Message> receive(String uri, String user, String pass, Date lastRequest){
		ArrayList<Message> retorno = new ArrayList<Message>();
		HttpClient cliente = new DefaultHttpClient();
		HttpPost post = new HttpPost(uri);
		HttpParams parametro = new BasicHttpParams();
		long id_request = Math.round(Math.random()*1000000);
		parametro.setParameter("", getRequestReceive(id_request,user,pass,lastRequest));
		post.setParams(parametro);
		try
		{
			HttpResponse respuesta = cliente.execute(post);
			HttpEntity contenido = respuesta.getEntity();
			retorno = getArrayReceive(EntityUtils.toString(contenido));
		} catch (ClientProtocolException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		return retorno;
	}
	
	public static String send(String uri, String user, String pass, String user_dest, String message){
		String retorno = "";
		HttpClient cliente = new DefaultHttpClient();
		HttpPost post = new HttpPost(uri);
		 
		long id_request = Math.round(Math.random()*1000000);
		try
		{
			StringEntity entity = new StringEntity(getRequestSend(id_request,user,pass,user_dest,message));
			post.setEntity(entity);
			HttpResponse respuesta = cliente.execute(post);
			HttpEntity contenido = respuesta.getEntity();
			retorno = getStatusSend(EntityUtils.toString(contenido));
		} catch (ClientProtocolException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		return retorno;
	}
	
	private static String getRequestReceive(long id, String user, String pass, Date lastRequest){
		XmlSerializer serializador = Xml.newSerializer();
		StringWriter xml = new StringWriter();
		try
		{
			serializador.setOutput(xml);
			serializador.startDocument("UTF-8", true);
			serializador.startTag("", "action");
			serializador.attribute("", "id", String.valueOf(id));
			serializador.attribute("", "name", "get-messages");
				serializador.startTag("", "action-detail");
					serializador.startTag("", "auth");
					serializador.attribute("", "username", user);
					serializador.attribute("", "key", pass);
					serializador.endTag("", "auth");
					serializador.startTag("", "filter");
					serializador.attribute("", "type", "timestamp");
						serializador.text(getTimestamp(lastRequest));
					serializador.endTag("", "filter");
				serializador.endTag("", "action-detail");
			serializador.endTag("", "action");
			serializador.flush();
		} catch (IllegalArgumentException e)
		{
			e.printStackTrace();
		} catch (IllegalStateException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		return xml.toString();
	}
	
	private static String getRequestSend(long id, String user, String pass, String user_dest, String message){
		XmlSerializer serializador = Xml.newSerializer();
		StringWriter xml = new StringWriter();
		try
		{
			serializador.setOutput(xml);
			serializador.startDocument("UTF-8", false);
			serializador.startTag("", "action");
			serializador.attribute("", "id", String.valueOf(id));
			serializador.attribute("", "name", "send-message");
				serializador.startTag("", "action-detail");
					serializador.startTag("", "auth");
					serializador.attribute("", "username", user);
					serializador.attribute("", "key", pass);
					serializador.endTag("", "auth");
					serializador.startTag("", "message");
					serializador.attribute("", "to", user_dest);
						serializador.cdsect(message);
					serializador.endTag("", "message");
				serializador.endTag("", "action-detail");
			serializador.endTag("", "action");
			serializador.flush();
		} catch (IllegalArgumentException e)
		{
			e.printStackTrace();
		} catch (IllegalStateException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		return xml.toString();
	}
	
	private static ArrayList<Message> getArrayReceive(String content){
		ArrayList<Message> retorno = new ArrayList<Message>();
		try
		{
			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document doc = builder.parse(new InputSource(new StringReader(content)));
			XPathExpression expr = XPathFactory.newInstance().newXPath().compile("//message");
			NodeList mensajes = (NodeList)expr.evaluate(doc, XPathConstants.NODESET);
			for(int i=0; i<mensajes.getLength(); i++){
				Node mensaje = mensajes.item(i);
				NamedNodeMap atributos = mensaje.getAttributes();
				String usuario = atributos.getNamedItem("from").getNodeValue();
				Date timestamp = getTimestamp(atributos.getNamedItem("timestamp").getNodeValue());
				Message msg = new MessageSenderClient().new Message(timestamp, usuario, mensaje.getTextContent());
				retorno.add(msg);
			}
		} catch (SAXException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		} catch (XPathExpressionException e)
		{
			e.printStackTrace();
		} catch (DOMException e)
		{
			e.printStackTrace();
		} catch (ParserConfigurationException e)
		{
			e.printStackTrace();
		}
		return retorno;
	}
	
	private static String getStatusSend(String content){
		String retorno = "";
		try
		{
			DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			Document doc = builder.parse(new InputSource(new StringReader(content)));
			XPathExpression exprStatus = XPathFactory.newInstance().newXPath().compile("//result/@type");
			retorno = ((Node)exprStatus.evaluate(doc, XPathConstants.NODE)).getTextContent();
			if(retorno.equalsIgnoreCase("error")){
				XPathExpression exprError = XPathFactory.newInstance().newXPath().compile("//detail/@description");
				Node error = ((Node)exprError.evaluate(doc, XPathConstants.NODE));
				if( error != null )
					retorno = error.getTextContent();
			}
		} catch (SAXException e)
		{
			e.printStackTrace();
			retorno = "Internal Failure";
		} catch (IOException e)
		{
			e.printStackTrace();
			retorno = "Internal Failure";
		} catch (XPathExpressionException e)
		{
			e.printStackTrace();
			retorno = "Internal Failure";
		} catch (DOMException e)
		{
			e.printStackTrace();
			retorno = "Internal Failure";
		} catch (ParserConfigurationException e)
		{
			e.printStackTrace();
			retorno = "Internal Failure";
		}
		return retorno;
	}
	
	public class Message {
		private Date timestamp;
		private String user;
		private String message;
		
		public Message(Date timestamp, String user, String message){
			this.timestamp = timestamp;
			this.user = user;
			this.message = message;
		}
		
		public Date getTimestamp(){
			return timestamp;
		}
		
		public String getUser() {
			return user;
		}
		
		public String getMessage(){
			return message;
		}
		
	}

}
